import { add, calcDiv, calcMul, calcSub, isValidNumber } from './NumberUtils';

/**
 * Number链式操作
 *
 * <p>包括数值的四则运算与格式化操作</p>
 *
 * @since V1.2.0
 *
 * ```
 * const res = new NumberChain(100).numberAdd(0.1).numberSub(0.2).numberMul(300).numberDiv(5).numberFmt('.4');
 * console.log(res); // output: 5,994.0000
 * ```
 */
export class NumberChain {

    private _value: any;

    constructor(value: any = null) {
        this.setValue(value || 0);
    }

    getValue(): any {
        return this._value;
    }

    setValue(value: any) {
        const v = value ? JSON.parse(JSON.stringify(value.toString())) : 0;
        if (isValidNumber(v)) {
            this._value = Number(v);
        } else {
            throw Error(`An error occurred in DecimalChain constructor(). Parameter value cannot be converted to decimal.`);
        }
    }

    /**
     * 数值加法操作
     * @param arg 相加的数值
     * @return NumberChain NumberChain实例
     */
    numberAdd(arg: number): NumberChain {
        this._value = add(this._value, arg);
        return this;
    }

    /**
     * 数值减法操作
     * @param arg 减数
     * @return NumberChain NumberChain实例
     */
    numberSub(arg: number): NumberChain {
        this._value = calcSub(this._value, arg);
        return this;
    }

    /**
     * 数值乘法操作
     * @param arg 乘数
     * @return NumberChain NumberChain实例
     */
    numberMul(arg: number): NumberChain {
        this._value = calcMul(this._value, arg);
        return this;
    }

    /**
     * 数值除法操作
     * @param arg 除数
     * @return NumberChain NumberChain实例
     */
    numberDiv(arg: number): NumberChain {
        this._value = calcDiv(this._value, arg);
        return this;
    }

    /**
     * 十进制数值格式化
     *
     * @param numPadFmt 数值补充格式，将数值的整数/小数部分补充到一定的长度
     *
     * <p>格式：minIntPartLength.minDecimalPartLength</p>
     * <ul>
     *   <li>minIntPartLength - 整数部分最小长度，数字类型</li>
     *   <li>minDecimalPartLength - 小数部分最小长度，数字类型</li>
     * </ul>
     *
     * <p>注：当上述两值为非数字字符时，保留原整数/小数部分长度，即不对数值长度/精度做处理</p>
     */
    numberFmt(numPadFmt = ''): string {
        let tmpValue = this._value.toString();
        let signBit = ''; // 符号位
        if (['+', '-'].includes(tmpValue.charAt(0))) { // 判断参数是否存在符号位
            signBit = tmpValue.charAt(0);
            tmpValue = tmpValue.substring(1);
        }
        // 根据小数点将数值分隔成整数部分和小数部分
        let intPartStr: string = tmpValue.split('.')[0]; // 整数部分
        let dcmPartStr: string = tmpValue.split('.')[1]; // 小数部分
        // 根据numPadFmt对数据进行补充处理
        if (numPadFmt) {
            const intPadLength = numPadFmt.toString().split('.')[0];
            if (isValidNumber(intPadLength)) {
                intPartStr = (intPartStr || '').padStart(Number(intPadLength), '0');
            }
            const dcmPadLength = numPadFmt.toString().split('.')[1];
            if (dcmPadLength && isValidNumber(dcmPadLength)) {
                dcmPartStr = (dcmPartStr || '').padEnd(Number(dcmPadLength), '0');
            }
        }
        // 对整数部分进行处理
        const intPartRvsList = intPartStr.split('').reverse();
        const tmpList: string[] = [];
        intPartRvsList.forEach((curValue, i) => {
            tmpList.push(curValue);
            if ((i + 1) % 3 === 0 && (i + 1) !== intPartRvsList.length) {
                tmpList.push(',');
            }
        });
        return signBit + tmpList.reverse().join('') + (dcmPartStr ? `.${dcmPartStr}` : '');
    }

}
